<?php

class CCoreBaseStreamWrapper
{
	/**
	 * @var	array
	 */
	static $aRegValues;

	/**
	 * @var	int
	 */
	private $iPos;

	/**
	 * @var	string
	 */
	private $_sStreamValue;

	/**
	 * @var	string
	 */
	private $_sStreamMode;

	/**
	 * @var	string
	 */
	private $_bOnlyWrite;

	/**
	 * @param	string	$sName
	 * @param	string	&$sValue
	 */
	public static function RegValue($sName, &$sValue)
	{
		if (!is_array(self::$aRegValues))
		{
			self::$aRegValues = array();
		}
		self::$aRegValues[$sName] =& $sValue;
	}

	/**
	 * @param	string	$sName
	 * @return	string | false
	 */
	public static function &GetValue($sName)
	{
		if (isset(self::$aRegValues[$sName]))
		{
			return self::$aRegValues[$sName];
		}

		$bFalse = false;
		return $bFalse;
	}

	/**
	 * @param	string	$sName
	 */
	public static function UnregValue($sName)
	{
		if (isset(self::$aRegValues[$sName]))
		{
			unset(self::$aRegValues[$sName]);
		}
	}
	
	/**
	 * @return	bool
	 */
	public static function RegWrapperStream()
	{
		if (!in_array('ccore', stream_get_wrappers()))
		{
			return stream_wrapper_register('ccore', 'CCoreBaseStreamWrapper');
		}

		return true;
	}

	private function _initOpenMode($sMode)
	{
		$this->_sStreamMode = $sMode;
		switch (true)
		{
			case (false !== strpos($this->_sStreamMode, 'r')):
				$this->iPos = 0;
				break;
			case (false !== strpos($this->_sStreamMode, 'w')):
				$this->_sStreamValue = '';
				$this->iPos = 0;
				break;
			case (false !== strpos($this->_sStreamMode, 'a')):
				$this->iPos = strlen($this->_sStreamValue);
				break;
			case (false !== strpos($this->_sStreamMode, 'x')):
				$this->iPos = 0;
				break;
		}
		
		$this->_bOnlyWrite = (false !== strpos($this->_sStreamMode, '+'));
	}

	/**
	 * @param	string	$sPath
	 * @param	string	$sMode
	 * @param	int		$iOptions
	 * @param	string	&$sOpenedPath
	 * @return	bool
	 */
	public function stream_open($sPath, $sMode, $iOptions, &$sOpenedPath)
	{
		$aPath = array('host' => '');
		$aPath = parse_url($sPath);
		$this->_sStreamValue =& self::GetValue($aPath['host']);
		$this->_initOpenMode($sMode);
		return is_string($this->_sStreamValue);
	}

	/**
	 * @param	int		$iCount
	 * @return	string
	 */
	public function stream_read($iCount)
	{
		//if ($this->_bOnlyWrite)
		//{
			$sReadResult = substr($this->_sStreamValue, $this->iPos, $iCount);
			$this->iPos += strlen($sReadResult);
			return $sReadResult;
		//}
		//return false;
	}

	/**
	 * @param	string	$sData
	 * @return	int
	 */
	public function stream_write($sData)
	{
		$iLen = strlen($sData);
		$this->_sStreamValue =
			substr($this->_sStreamValue, 0, $this->iPos).
			$sData.
			substr($this->_sStreamValue, $this->iPos += $iLen);

		return $iLen;
	}

	/**
	 * @return	int
	 */
	public function stream_tell()
	{
		return $this->iPos;
	}

	/**
	 * @return	bool
	 */
	public function stream_eof()
	{
		return $this->iPos >= strlen($this->_sStreamValue);
	}

	public function stream_stat()
	{
		return array(
			'dev' => 2,
			'ino' => 0,
			'mode' => 33206,
			'nlink' => 1,
			'uid' => 0,
			'gid' => 0,
			'rdev' => 2,
			'size' => strlen($this->_sStreamValue),
			'atime' => 1061067181,
			'mtime' => 1056136526,
			'ctime' => 1056136526,
			'blksize' => -1,
			'blocks' => -1
		);
	}

	/**
	 * @param	int		$iOffset
	 * @param	int		$iWhence
	 * @return	bool
	 */
	public function stream_seek($iOffset, $iWhence)
	{
		$iLen = strlen($this->_sStreamValue);

		$iNewPos = 0;
		switch ($iWhence)
		{
			case SEEK_SET:
				$iNewPos = $iOffset;
				break;
			case SEEK_CUR:
				$iNewPos = $this->iPos + $iOffset;
				break;
			case SEEK_END:
				$iNewPos = $iLen + $iOffset;
				break;
			default:
				return false;
		}
		$bReturn = ($iNewPos >= 0 && $iNewPos <= $iLen);
		if ($bReturn)
		{
			$this->iPos = $iNewPos;
		}
		return $bReturn;
	}
}

CCoreBaseStreamWrapper::RegWrapperStream();